package edu.suda.basic.media;

import java.io.File;
import java.util.Iterator;
import java.text.DecimalFormat;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;

import javax.swing.*;
import javax.media.jai.JAI;
import javax.media.jai.RenderedOp;
import javax.media.jai.PlanarImage;

import no.geosoft.cc.geometry.Geometry;
import no.geosoft.cc.util.NiceNumbers;
import no.geosoft.cc.util.NiceNumber;
import no.geosoft.cc.graphics.*;

/**
 * G demo program. Demonstrates:
 * 
 * <ul>
 * </ul>
 * 
 * @author <a href="mailto:jacob.dreyer@geosoft.no">Jacob Dreyer</a>
 */
public class Demo18 extends JFrame
{
	/**
	 * Class for creating the demo canvas and hande Swing events.
	 */
	public Demo18(String imageFile, int minCdp, int maxCdp, int minTime, int maxTime)
	{
		super("G Graphics Library - Demo 18");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		// Create the GUI
		JPanel topLevel = new JPanel();
		topLevel.setLayout(new BorderLayout());
		getContentPane().add(topLevel);

		JScrollBar hScrollBar = new JScrollBar(JScrollBar.HORIZONTAL);
		getContentPane().add(hScrollBar, BorderLayout.SOUTH);

		JScrollBar vScrollBar = new JScrollBar(JScrollBar.VERTICAL);
		getContentPane().add(vScrollBar, BorderLayout.EAST);

		// Create the graphic canvas
		GWindow window = new GWindow(new Color(255, 255, 255));
		topLevel.add(window.getCanvas(), BorderLayout.CENTER);

		// Definition of exact chart location inside window
		Insets insets = new Insets(80, 60, 20, 20);

		// Create a value specific image scene
		GScene seismicScene = new SeismicScene(window, imageFile, minCdp, maxCdp, minTime, maxTime, insets);

		// Create a "background" device oriented annotation scene
		GScene annotationScene = new GScene(window);
		GObject annotation = new Annotation(insets);
		annotationScene.add(annotation);
		annotationScene.setUserData(seismicScene);

		pack();
		setSize(new Dimension(500, 500));
		setVisible(true);

		// Start zoom interaction
		GStyle zoomStyle = new GStyle();
		zoomStyle.setForegroundColor(new Color(0, 0, 0));
		zoomStyle.setBackgroundColor(new Color(0.8f, 1.0f, 0.8f, 0.3f));
		window.startInteraction(new ZoomInteraction(seismicScene, zoomStyle));

		// Make sure plot can be scrolled
		seismicScene.installScrollHandler(hScrollBar, vScrollBar);
	}

	private class Annotation extends GObject
	{
		private Insets insets_;
		private GSegment title_;

		public Annotation(Insets insets)
		{
			insets_ = insets;

			title_ = new GSegment();
			GStyle titleStyle = new GStyle();
			titleStyle.setForegroundColor(new Color(0, 0, 0));
			titleStyle.setFont(new Font("Dialog", Font.BOLD, 20));
			title_.setStyle(titleStyle);
			title_.setText(new GText("Inline 220"));
			addSegment(title_);

			GStyle axisStyle = new GStyle();
			axisStyle.setForegroundColor(new Color(0.0f, 0.0f, 0.0f, 0.4f));
			axisStyle.setBackgroundColor(null);
			axisStyle.setFont(new Font("Dialog", Font.BOLD, 10));

			Axis horizontalAxis = new Axis(true, insets_);
			horizontalAxis.setStyle(axisStyle);
			add(horizontalAxis);

			Axis verticalAxis = new Axis(false, insets_);
			verticalAxis.setStyle(axisStyle);
			add(verticalAxis);
		}

		public void draw()
		{
			GViewport viewport = getScene().getViewport();

			int x0 = insets_.left;
			int y0 = insets_.top;
			int width = viewport.getX3() - insets_.right - insets_.left + 1;
			int height = viewport.getY3() - insets_.bottom - insets_.top + 1;

			// Draw title
			title_.setGeometry(x0 + width / 2, y0 / 2);
		}
	}

	/**
	 * A GObject representing one axis with annotation.
	 */
	private class Axis extends GObject
	{
		private Insets insets_;
		private boolean isTop_;

		public Axis(boolean isTop, Insets insets)
		{
			isTop_ = isTop;
			insets_ = insets;
		}

		public void draw()
		{
			removeSegments();

			// Get device coordinates
			GViewport viewport = getScene().getViewport();

			int vx0 = insets_.left;
			int vy0 = insets_.top;
			int vx1 = viewport.getX3() - insets_.right;
			int vy1 = viewport.getY3() - insets_.bottom;

			// Get annotation range
			GObject plot = (GObject) getScene().getUserData();
			if (plot == null)
				return;

			GWorldExtent worldExtent = plot.getScene().getWorldExtent();

			double[] w0 = worldExtent.get(0);
			double[] w1 = worldExtent.get(1);
			double[] w2 = worldExtent.get(2);

			// Prepare axis values
			double from = isTop_ ? w0[0] : w2[1];
			double to = isTop_ ? w1[0] : w0[1];

			int x0 = vx0;
			int y0 = vy0;
			int x1 = isTop_ ? vx1 : x0;
			int y1 = isTop_ ? y0 : vy1;

			double length = Geometry.length(x0, y0, x1, y1);
			int n = (int) (length / 50.0);

			NiceNumbers niceNumbers = new NiceNumbers(from, to, n, true);

			DecimalFormat format = new DecimalFormat("0");

			for (Iterator i = niceNumbers.iterator(); i.hasNext();)
			{
				NiceNumber niceNumber = (NiceNumber) i.next();

				int rank = niceNumber.getRank();
				if (rank < 2)
				{
					int tickLength = rank == 0 ? 5 : 3;

					GSegment tick = new GSegment();
					int tx0 = isTop_ ? x0 + (int) Math.round(niceNumber.getPosition() * (x1 - x0)) : x0 - tickLength;
					int ty0 = isTop_ ? y0 - tickLength : y0 + (int) Math.round(niceNumber.getPosition() * (y1 - y0));
					int tx1 = isTop_ ? tx0 : (rank == 0 ? vx1 : x0);
					int ty1 = isTop_ ? (rank == 0 ? vy1 : y0) : ty0;
					tick.setGeometry(tx0, ty0, tx1, ty1);

					if (rank == 0)
					{
						double value = niceNumber.getValue();
						GText text = new GText(format.format(value), isTop_ ? GPosition.TOP : GPosition.LEFT);
						tick.setText(text);
					}

					addSegment(tick);
				}
			}
		}
	}

	private class SeismicSection extends GObject
	{
		private GSegment anchor_;
		private BufferedImage image_;

		SeismicSection(String seismicImage)
		{
			anchor_ = new GSegment();
			addSegment(anchor_);

			RenderedOp renderedOp = JAI.create("FileLoad", seismicImage);
			PlanarImage planarImage = renderedOp.createInstance();
			image_ = planarImage.getAsBufferedImage();
		}

		public void draw()
		{
			GViewport viewport = getScene().getViewport();
			anchor_.setGeometry(viewport.getX0(), viewport.getY0());

			GWorldExtent worldExtent = getScene().getWorldExtent();
			double[] w2 = worldExtent.get(2);

			int x0 = (int) w2[0] - 1;
			int y0 = ((int) w2[1] - 1000) / 4;

			int width = (int) worldExtent.getWidth();
			int height = (int) worldExtent.getHeight() / 4;

			// Pick the part of the source image to show
			BufferedImage subImage = image_.getSubimage(x0, y0, width, height);

			// Scale it to the viewport
			int viewportWidth = (int) viewport.getWidth();
			int viewportHeight = (int) viewport.getHeight();

			Image scaledImage = subImage.getScaledInstance(viewportWidth, viewportHeight, Image.SCALE_AREA_AVERAGING);

			GImage image = new GImage(scaledImage, GPosition.SOUTHEAST | GPosition.STATIC);

			anchor_.setImage(image);
		}
	}

	/**
	 * Defines the geometry and presentation for a sample graphic object.
	 */
	private class SeismicScene extends GScene
	{
		private Insets insets_;

		SeismicScene(GWindow window, String seismicImage, int minCdp, int maxCdp, int minTime, int maxTime, Insets insets)
		{
			super(window);

			insets_ = insets;

			double w0[] =
			{ (double) minCdp, (double) maxTime, 0.0 };
			double w1[] =
			{ (double) maxCdp, (double) maxTime, 0.0 };
			double w2[] =
			{ (double) minCdp, (double) minTime, 0.0 };
			setWorldExtent(w0, w1, w2);

			SeismicSection seismicSection = new SeismicSection(seismicImage);
			add(seismicSection);
		}

		protected void resize(double dx, double dy)
		{
			super.resize(dx, dy);
			setViewport(insets_.left, insets_.top, getWindow().getWidth() - insets_.left - insets_.right, getWindow().getHeight() - insets_.top - insets_.bottom);
		}
	}

	public static void main(String[] args)
	{
		if (args.length != 5)
		{
			System.out.println("Parameters: imageFile minCDP maxCDP minTime maxTime");
			System.exit(0);
		}

		new Demo18(args[0], Integer.parseInt(args[1]), Integer.parseInt(args[2]), Integer.parseInt(args[3]), Integer.parseInt(args[4]));
	}
}
